<template>
  <div class="main">
    <div id="cesiumContainer"></div>
  </div>
</template>

<script>
var Cesium = require("cesium/Cesium");
import "../../../node_modules/cesium/Source/Widgets/widgets.css";
import $ from "jquery";
import * as turf from "@turf/turf";
export default {
  name: "Map",
  data() {
    return {
      // viewer: "",
      position: "",
      center: "",
      reBbox: {
        //大余县外接矩形的Bbox
        minx: 114.00029582000024,
        miny: 25.256412020000132,
        maxx: 114.68747202800001,
        maxy: 25.623771009999994,
      },
      extend: {}, //屏幕可视范围的东西南北
      length: "", //切分出来的每个小网格的高
      cameraHeight: "", //相机的高度
      width: "", //切分出来的每个小网格的宽
      removeKey: [],//加载过的网格的编号
      url2: "http://wx.gisocn.com:30560/geoserver/cite/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=cite%3Adayu_building_merge1&outputFormat=application%2Fjson",
    };
  },
  mounted() {
    var that = this;
    Cesium.Ion.defaultAccessToken =
      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4MTFmZTI3MC1hZTE0LTRmYzctYTIwMy1lMjQ1ZjgxMGRhM2UiLCJpZCI6NzI4ODQsImlhdCI6MTYzNjQ0MjcyNH0.i6q-HiknfKeuLMD-rMBZ751jBnSCzqC0nHtDpZkaBu0";
    // WebMapServiceImageryProvider
    // ArcGisMapServerImageryProvider
    let maplayer = new Cesium.ArcGisMapServerImageryProvider({
      url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
    });
    var viewer = new Cesium.Viewer("cesiumContainer", {
      animation: false, //是否显示动画插件
      shouldAnimation: false, //是否自动显示动画（下方时间轴是不是在走着）
      homeButton: false, //是否显示home按钮
      fullscreenButton: false, // 是否显示全屏按钮
      baseLayerPicker: false, // 是否显示图层选择控件
      geocoder: false, // 是否显示地名查找控件
      timeline: false, // 是否显示时间线控件
      sceneModePicker: false, // 是否显示投影方式控件（右上角的小圆球）
      navigationHelpButton: false, // 是否显示帮助信息控件
      infoBox: false, // 是否显示点击要素之后显示的信息
      sceneMode: 3, // 初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneMode
      selectionIndicator: false, //选中指示框
      navigationInstructionsInitiallyVisible: false, // 帮助按钮，初始化的时候是否展开
      mapProjection: new Cesium.WebMercatorProjection(), //地图投影体系
      terrainProvider: Cesium.createWorldTerrain(), //地形图层提供者，仅baseLayerPicker设为false有意义
      contextOptions: {
        webgl: {
          alpha: true,
          depth: true,
          stencil: true,
          antialias: true,
          premultipliedAlpha: true,
          //通过canvas.toDataURL()实现截图需要将该项设置为true
          preserveDrawingBuffer: true,
          failIfMajorPerformanceCaveat: true,
        },
      },
    });
    window.viewer = viewer;
    window.viewer.scene.imageryLayers.addImageryProvider(maplayer); //去除谷歌请求
    // window.viewer.imageryLayers.addImageryProvider(annLayer); //图层类型的添加
    window.viewer.imageryLayers.get(0).show = true; //添加图层
    window.viewer._cesiumWidget._creditContainer.style.display = "none"; // 去除版权信息
    // window.viewer.scene.globe.depthTestAgainstTerrain = true; //地形遮挡(深度监测)
    window.viewer.scene.globe.enableLighting = false; //是否使用地球光照
    window.viewer.scene.globe.showGroundAtmosphere = false; //绘制在地球上的地面大气。
    window.viewer.terrainProvider = Cesium.createWorldTerrain({
      //启用地形照明和水体效果
      requestWaterMask: true,
      requestVertexNormals: true,
    });
    window.viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(114.352497, 25.401622, 1500),
      orientation: {
        heading: Cesium.Math.toRadians(0.0),
        pitch: Cesium.Math.toRadians(-90.0),
        roll: Cesium.Math.toRadians(0.0),
      },
      duration: 5, //飞行时间value
    });
    // 将大余县外接矩形x,y,方向各切分500次，并给切分得到的每个小网格赋予相应的编号
    this.length = (that.reBbox.maxy - that.reBbox.miny) / 300; //每个小网格的高
    this.width = (that.reBbox.maxx - that.reBbox.minx) / 300; //每个小网格的
    this.deviation();
    this.grid()
  },
  methods: {
    deviation() {
      var dataMap = new Map();
      var that = this;
      var bl = 0; //记录移动的次数
      window.viewer.scene.camera.moveEnd.addEventListener(function () {
        that.cameraHeight = window.viewer.camera._positionCartographic.height
        console.log(that.cameraHeight)
        let remove = []; //当前可视范围内所有网格的编号
        if (that.cameraHeight < 3000) {//判断相机高度
          var scene = window.viewer.scene;
          // 得到当前三维场景的椭球体
          var ellipsoid = scene.globe.ellipsoid;
          var canvas = scene.canvas;
          // canvas左上角
          var car3_lt = window.viewer.camera.pickEllipsoid(
            new Cesium.Cartesian2(0, 0),
            ellipsoid
          );
          // canvas右下角
          var car3_rb = window.viewer.camera.pickEllipsoid(
            new Cesium.Cartesian2(canvas.width, canvas.height),
            ellipsoid
          );
          //左下
          var car3_lb = window.viewer.camera.pickEllipsoid(
            new Cesium.Cartesian2(0, canvas.height),
            ellipsoid
          );
          //右上
          var car3_rt = window.viewer.camera.pickEllipsoid(
            new Cesium.Cartesian2(canvas.width, 0),
            ellipsoid
          );
          var pitch = window.viewer.camera.pitch;
          pitch = (pitch / Math.PI) * 180;
          console.log(pitch);
          // console.log(car3_lt)
          // console.log(car3_rb)
          // console.log(car3_lb)
          // console.log(car3_rt)
          // console.log(that.reBbox)
          if (car3_lt && car3_rb) {
            //判断屏幕的四个点是否都在地图上
            var carto_lt = ellipsoid.cartesianToCartographic(car3_lt);
            var carto_rb = ellipsoid.cartesianToCartographic(car3_rb);
            var carto_lb = ellipsoid.cartesianToCartographic(car3_lb);
            var carto_rt = ellipsoid.cartesianToCartographic(car3_rt);
            var leftTop = {}; //左上角经纬度坐标
            leftTop.lon = Cesium.Math.toDegrees(carto_lt.longitude);
            leftTop.lat = Cesium.Math.toDegrees(carto_lt.latitude);
            // console.log(leftTop)
            var rightTop = {}; //右上角经纬度坐标
            rightTop.lon = Cesium.Math.toDegrees(carto_rt.longitude);
            rightTop.lat = Cesium.Math.toDegrees(carto_rt.latitude);
            var leftBottom = {}; //左下角经纬度坐标
            leftBottom.lon = Cesium.Math.toDegrees(carto_lb.longitude);
            leftBottom.lat = Cesium.Math.toDegrees(carto_lb.latitude);
            var rightBottom = {}; //右下角经纬度坐标
            rightBottom.lon = Cesium.Math.toDegrees(carto_rb.longitude);
            rightBottom.lat = Cesium.Math.toDegrees(carto_rb.latitude);
            // console.log(leftTop)
            // console.log(rightTop)
            // console.log(rightBottom)
            // console.log(leftBottom)

            if (Math.abs(pitch) >= 45 && Math.abs(pitch) <= 90) {//判断相机的倾斜程度
              
              // //<----测试代码---->
              // // 打点查看屏幕的四个点在网格中的位置(用于测试)
              // if(bl>0){
              //   window.viewer.entities.add({//左上角
              //     position:Cesium.Cartesian3.fromDegrees(leftTop.lon,leftTop.lat),
              //     point:{
              //       pixelSize:10,
              //       color:Cesium.Color.RED
              //     }
              //   })
              //   window.viewer.entities.add({//右上角
              //     position:Cesium.Cartesian3.fromDegrees(rightTop.lon,rightTop.lat),
              //     point:{
              //       pixelSize:10,
              //       color:Cesium.Color.RED
              //     }
              //   })
              //   window.viewer.entities.add({//左下角
              //     position:Cesium.Cartesian3.fromDegrees(leftBottom.lon,leftBottom.lat),
              //     point:{
              //       pixelSize:10,
              //       color:Cesium.Color.RED
              //     }
              //   })
              //   window.viewer.entities.add({//右下角
              //     position:Cesium.Cartesian3.fromDegrees(rightBottom.lon,rightBottom.lat),
              //     point:{
              //       pixelSize:10,
              //       color:Cesium.Color.RED
              //     }
              //   })
              // }
              // //<----测试代码---->

              // 计算得到屏幕范围左上角的点所在网格的编号
              let dxl = Math.abs(that.reBbox.minx - leftTop.lon); //外接矩形的minx到可视范围的minx的距离
              let dyl = Math.abs(that.reBbox.maxy - leftTop.lat); //外接矩形的maxy到可视范围的maxy的距离
              // x方向：//Math.ceil：向上取整、Math.floor：向下取整
              let dxKey = Math.floor(dxl / that.width); //左上角横向(向下取整)
              // y方向：
              let dyKey = Math.floor(dyl / that.length); //左上角纵向(向下取整)
              
              // 计算得到右上角的点所在网格的编号
              let dxrt = Math.abs(that.reBbox.minx - rightTop.lon)
              let dyrt = Math.abs(that.reBbox.maxy - rightTop.lat)
              let dxKeyrt = Math.floor(dxrt / that.width); //x方向
              let dyKeyrt = Math.floor(dyrt / that.length); //y方向
              

              // 计算得到左下角的点所在网格的编号
              let dxlb = Math.abs(that.reBbox.minx - leftBottom.lon)
              let dylb = Math.abs(that.reBbox.maxy - leftBottom.lat)
              let dxKeylb = Math.floor(dxlb / that.width); //x方向编号
              let dyKeylb = Math.floor(dylb / that.length); //y方向编号

              //计算得到屏幕范围右下角的点所在网格的编号
              let dxr = Math.abs(that.reBbox.minx - rightBottom.lon); //外接矩形的minx到可视范围的maxx的距离
              let dyr = Math.abs(that.reBbox.maxy - rightBottom.lat); //外接矩形的maxy到可视范围的miny的距离
              let dxKeyr = Math.floor(dxr / that.width); //x方向
              let dyKeyr = Math.floor(dyr / that.length); //y方向
              
              //x方向: 左上:Bboxlt.keyx  右上:Bboxrt.keyx  左下:Bboxlb.keyx  右下:Bboxrb.keyx
              // y方向:左上:Bboxlt.keyy  右上:Bboxrt.keyy  左下:Bboxlb.keyy  右下:Bboxrb.keyy
              // 比较x方向四个点得到key值的最大最小值(min->max)
              // 比较y方向四个点得到key值的最大最小值(min->max)
              let xkeyArray = [dxKey,dxKeyrt,dxKeylb,dxKeyr]
              let ykeyArray = [dyKey,dyKeyrt,dyKeylb,dyKeyr]
              let maxxkey = Math.max(...xkeyArray)//x方向最大key
              let minxkey = Math.min(...xkeyArray)//x方向最小key
              let maxykey = Math.max(...ykeyArray)//y方向最大key
              let minykey = Math.min(...ykeyArray)//y方向最小key
              var Circumscribedmin = {}//xy方向key值最小的网格的坐标(外接矩形的左上角所在网格)
              Circumscribedmin.minx = that.reBbox.minx + minxkey * that.width;
              Circumscribedmin.maxx = that.reBbox.minx + (minxkey + 1) * that.width;
              Circumscribedmin.miny = that.reBbox.maxy - (minykey + 1) * that.length;
              Circumscribedmin.maxy = that.reBbox.maxy - minykey * that.length;
              // //<----测试代码---->
              // if(bl>0){
              //   console.log("外接矩形：")
              //   console.log(Circumscribedmin)
              // }
              // var Circumscribedmax = {}//xy方向key值最大的网格的坐标(外接矩形右下角所在网格)
              // Circumscribedmax.minx = that.reBbox.minx + maxxkey * that.width;
              // Circumscribedmax.maxx = that.reBbox.minx + (maxxkey + 1) * that.width;
              // Circumscribedmax.miny = that.reBbox.maxy - (maxykey + 1) * that.length;
              // Circumscribedmax.maxy = that.reBbox.maxy - maxykey * that.length;
              // // 绘制倾斜后屏幕外接矩形的左上角所在的网格矩形(用于测试)
              // window.viewer.entities.add({
              //   polygon:{
              //     hierarchy:{
              //       positions:Cesium.Cartesian3.fromDegreesArray([
              //         Circumscribedmin.minx,Circumscribedmin.maxy,
              //         Circumscribedmin.minx,Circumscribedmin.miny,
              //         Circumscribedmin.maxx,Circumscribedmin.miny,
              //         Circumscribedmin.maxx,Circumscribedmin.maxy
              //       ])
              //     },
              //     outline:true,//边框
              //     outlineColor:Cesium.Color.fromCssColorString('#000'),//边框的颜色
              //     outlineWidth:2,//边框的宽度
              //     material:Cesium.Color.PINK.withAlpha(0.5),//填充颜色、透明度
              //     fill:true,//是否被提供的材质填充
              //     height:0,//恒定高度
              //     // distanceDisplayCondition:new Cesium.DistanceDisplayCondition(1000,1000000),//显示在距相机的距离处的属性（在多少区间内可以显示）
              //     show:true,//是否显示
              //     zIndex:10,//顺序
              //   }
              // })
              // // 绘制倾斜后外接矩形的右下角的网格矩形（用于测试）
              // window.viewer.entities.add({
              //   polygon:{
              //     hierarchy:{
              //       positions:Cesium.Cartesian3.fromDegreesArray([
              //         Circumscribedmax.minx,Circumscribedmax.maxy,
              //         Circumscribedmax.minx,Circumscribedmax.miny,
              //         Circumscribedmax.maxx,Circumscribedmax.miny,
              //         Circumscribedmax.maxx,Circumscribedmax.maxy
              //       ])
              //     },
              //     outline:true,//边框
              //     outlineColor:Cesium.Color.fromCssColorString('#000'),//边框的颜色
              //     outlineWidth:2,//边框的宽度
              //     material:Cesium.Color.BLUE.withAlpha(0.5),//填充颜色、透明度
              //     fill:true,//是否被提供的材质填充
              //     height:0,//恒定高度
              //     // distanceDisplayCondition:new Cesium.DistanceDisplayCondition(1000,1000000),//显示在距相机的距离处的属性（在多少区间内可以显示）
              //     show:true,//是否显示
              //     zIndex:10,//顺序
              //   }
              // })
              // //<----测试代码---->
              
              let VisualRange = turf.polygon([
                [//可视范围
                  [leftTop.lon, leftTop.lat],
                  [rightTop.lon, rightTop.lat],
                  [rightBottom.lon, rightBottom.lat],
                  [leftBottom.lon, leftBottom.lat],
                  [leftTop.lon, leftTop.lat],
                ],
              ]);
              // console.log(VisualRange)
              for (var k = 0; k <= Math.abs(maxxkey - minxkey); k++) { //从左到右
                let bboxNew = {};
                bboxNew.minx = Circumscribedmin.minx + k * that.width;
                bboxNew.maxx = bboxNew.minx + that.width;
                var key1 = minxkey + k;
                if (key1 < 10) {
                  var a1 = "00" + key1;
                } else if (key1 < 100) {
                  var a1 = "0" + key1;
                } else if (key1 < 1000) {
                  var a1 = key1;
                }
                for (var j = 0; j <= Math.abs(maxykey - minykey); j++) {
                  var object = {};
                  var id = [];
                  bboxNew.miny = Circumscribedmin.miny - j * that.length;
                  bboxNew.maxy = bboxNew.miny + that.length;
                  // if(bl>0){
                  //   console.log("要加载的小网格：")
                  //   console.log(bboxNew)
                  // }
                  var bbox2 = bboxNew.minx + "," + bboxNew.miny + "," + bboxNew.maxx + "," + bboxNew.maxy;
                  var key2 = minykey + j;
                  if (key2 < 10) {
                    var b1 = "00" + key2;
                  } else if (key2 < 100) {
                    var b1 = "0" + key2;
                  } else if (key2 < 1000) {
                    var b1 = key2;
                  }
                  bboxNew.key = a1 + "" + b1;
                  // console.log(bboxNew.key)
                  var pointlt = turf.point([bboxNew.minx,bboxNew.maxy])
                  var pointlb = turf.point([bboxNew.minx,bboxNew.miny])
                  var pointrb = turf.point([bboxNew.maxx,bboxNew.miny])
                  var pointrt = turf.point([bboxNew.maxx,bboxNew.maxy])
                  // 判断网格的四个点是否至少有一个在可视范围的面内：
                  var isContainlt = turf.booleanPointInPolygon(pointlt,VisualRange); //网格左上角的点
                  var isContainlb = turf.booleanPointInPolygon(pointlb,VisualRange); //网格左下角的点
                  var isContainrb = turf.booleanPointInPolygon(pointrb,VisualRange); //网格右下角的点
                  var isContainrt = turf.booleanPointInPolygon(pointrt,VisualRange); //网格右上角的点
                  // console.log("if外:")
                  // console.log(isContainlt,isContainlb,isContainrb,isContainrt)
                  if (isContainlt==true ||isContainlb==true ||isContainrb==true ||isContainrt==true) {
                    // console.log("if内:")
                    // console.log(isContainlt,isContainlb,isContainrb,isContainrt)
                    remove.push(bboxNew.key);//当前可视范围内的网格编号
                    if (that.removeKey.indexOf(bboxNew.key) == -1) {
                      $.ajax({
                        url: that.url2,
                        data: {
                          bbox: bbox2,
                        },
                        async: false, //设置请求为同步请求
                        type: "get",
                        success: function (res) {
                          var datasource2 = Cesium.GeoJsonDataSource.load(res);
                          datasource2.then(function (source) {
                            if (window.viewer.dataSources._dataSources.length > 0) {//去重
                              // 计算相邻八个网格的编号
                              var leftTop = a1 - 1 + "" + (b1 - 1); //左上
                              var top = a1 + "" + (b1 - 1); //正上
                              var rightTop = a1 + 1 + "" + (b1 - 1); //右上
                              var left = a1 - 1 + "" + b1; //左
                              var right = a1 + 1 + "" + b1; //右
                              var leftBtm = a1 - 1 + "" + (b1 + 1); //左下
                              var bottom = a1 + "" + (b1 + 1); //下
                              var rightBtm = a1 + 1 + "" + (b1 + 1); //右下
                              let xlArray = [leftTop,top,rightTop,left,right,leftBtm,bottom,rightBtm,];
                              for (var xl = 0; xl < xlArray.length; xl++) {
                                let dataValue = dataMap.get(xlArray[xl]);
                                if (dataValue != undefined) {
                                  for (var d4 = 0;d4 < source.entities.values.length;d4++) {
                                    if (dataValue.indexOf(source.entities.values[d4]._id) != -1) {
                                      source.entities.values.splice(d4, 1);
                                      d4 = d4 - 1;
                                      // console.log(dataValue)
                                    }
                                  }
                                }
                              }
                            }
                            // 实体对象的id：source.entities.values[c]._id
                            // 1ms以内
                            for (var c = 0;c < source.entities.values.length;c++) {
                              id.push(source.entities.values[c]._id);
                              // window.viewer.entities.add(source.entities.values[c])
                            }
                            object.arrayId = id;
                            source._name = bboxNew.key;
                            window.viewer.dataSources.add(source);
                          });
                        },
                      });
                      object.key = bboxNew.key;
                      that.removeKey.push(bboxNew.key);
                      dataMap.set(object.key, object.arrayId); //map:(key,value)
                    }
                  }
                }
              }
              // 卸载
              // console.log(bl)
              var _dataSources = window.viewer.dataSources._dataSources;
              if (bl > 0) {
                //移动之后
                for (var a4 = 0; a4 < that.removeKey.length; a4++) {
                  // console.log(remove.indexOf(that.removeKey[a4]))
                  if (remove.indexOf(that.removeKey[a4]) == -1) {
                    // console.log("执行到了")
                    var valueId = dataMap.get(that.removeKey[a4]);
                    if (valueId != undefined) {
                      for (var i1 = 0; i1 < _dataSources.length; i1++) {
                        if (that.removeKey[a4] == _dataSources[i1]._name) {
                          // console.log(_dataSources[i1])
                          window.viewer.dataSources.remove(_dataSources[i1]);
                          // console.log("卸载了")
                        }
                      }
                    }
                    dataMap.delete(that.removeKey[a4]);
                    that.removeKey.splice(a4, 1);
                    a4 = a4 - 1;
                  }
                }
              }
              bl++;
            }
          }
        }
      });
    },
    grid() {//绘制网格
      var that = this
      for(var i=130;i<180;i++){
        let bboxGrid = {};
        bboxGrid.minx = that.reBbox.minx + i * that.width;
        bboxGrid.maxx = bboxGrid.minx + that.width;
        for(var j=160;j<210;j++){
          bboxGrid.miny = that.reBbox.maxy - j * that.length;
          bboxGrid.maxy = bboxGrid.miny + that.length;
          // 画面
          window.viewer.entities.add({//左上角
            polygon:{
              hierarchy:{
                positions:Cesium.Cartesian3.fromDegreesArray([
                  bboxGrid.minx,bboxGrid.maxy,
                  bboxGrid.minx,bboxGrid.miny,
                  bboxGrid.maxx,bboxGrid.miny,
                  bboxGrid.maxx,bboxGrid.maxy
                ])
              },
              outline:true,//边框
              outlineColor:Cesium.Color.fromCssColorString('#9fc5e8'),//边框的颜色
              outlineWidth:2,//边框的宽度
              material:Cesium.Color.PINK.withAlpha(0),//填充颜色、透明度
              fill:true,//是否被提供的材质填充
              height:0,//恒定高度
              // distanceDisplayCondition:new Cesium.DistanceDisplayCondition(1000,1000000),//显示在距相机的距离处的属性（在多少区间内可以显示）
              show:true,//是否显示
              zIndex:10,//顺序
            }
          })
          console.log("网格绘制成功")

        }
      }
      
          // window.viewer.entities.add({//左上角
          //   polygon:{
          //     hierarchy:{
          //       positions:Cesium.Cartesian3.fromDegreesArray([
          //         that.reBbox.minx,that.reBbox.maxy,
          //         that.reBbox.minx,that.reBbox.miny,
          //         that.reBbox.maxx,that.reBbox.miny,
          //         that.reBbox.maxx,that.reBbox.maxy
          //       ])
          //     },
          //     outline:true,//边框
          //     outlineColor:Cesium.Color.fromCssColorString('#9fc5e8'),//边框的颜色
          //     outlineWidth:2,//边框的宽度
          //     material:Cesium.Color.RED.withAlpha(0.5),//填充颜色、透明度
          //     fill:true,//是否被提供的材质填充
          //     height:0,//恒定高度
          //     // distanceDisplayCondition:new Cesium.DistanceDisplayCondition(1000,1000000),//显示在距相机的距离处的属性（在多少区间内可以显示）
          //     show:true,//是否显示
          //     zIndex:10,//顺序
          //   }
          // })
    }
  },
};
</script>

<style>
head {
  height: 0;
  margin: 0;
}
html,
body,
#app,
.main,
#cesiumContainer {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  font-family: sans-serif;
}
</style>